Skip to content

1877. 数组中最大数对和的最小值

1877. 数组中最大数对和的最小值

ts
function minPairSumUpdate(nums: number[]): number {
  nums.sort((a, b) => a - b)
  let max = 0
  const n = nums.length
  for (let i = 0; i < n / 2; i++) {
    const sum = nums[i] + nums[n - 1 - i]
    if (sum > max) max = sum
  }
  return max
}

这题要压的不是总和,而是所有配对里的最大值。目标一变,配对策略就很固定了:不能让大数和大数撞在一起,否则峰值会被直接抬高。

排序后首尾配对,本质是在做极值对冲。最小的去接最大的,次小的去接次大的,结果不是让每一对都最小,而是让最坏的那一对别太离谱。这个思路比“贪心”两个字本身更值得记。

为什么不是相邻配

如果把排好序的数组相邻配,比如 1,2,3,4 配成 (1,2)(3,4),最大 pair sum 是 7
首尾配 (1,4)(2,3),最大 pair sum 变成 5

这里实际在避免一件事:大的值聚集。只要大值集中在同一对里,答案就会被那一对决定。把大值拆开,分别交给小值去吸收,最大值才会下降。

换个更抽象的看法,设 a <= b <= c <= d

  • 相邻配时是 (a, b)(c, d)
  • 首尾配时是 (a, d)(b, c)

后一种配法不会让“较大的那个和”变得更差,通常还更小。局部成立,整体就自然落到双指针头尾配。

代码上没什么花样

排序后扫前半段,和后半段镜像位置配对就够了。

  • nums[i]
  • nums[n - 1 - i]

每次更新当前最大的 pair sum,最后返回它。

初始版本用双指针 pre/aft 写也一样,只是 for 版更贴近这个题的结构,看起来负担更小。

一个小前提

这里 max 初始化成 0 是因为题目里的 nums[i] 都是正数。
如果题目允许负数,这种写法就不稳了,应该初始化成第一对的和,或者 -Infinity

复杂度

  • 时间复杂度:O(n log n),主要是排序
  • 空间复杂度:取决于排序实现,通常记作 O(log n) 或语言相关

这题真正该留下来的只有一句话:

当目标是最小化“配对结果里的最大值”时,优先考虑把大值和小值绑定,而不是让相近量级的值聚在一起。